// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ManageSettingsForm.cs" company="Roman '4ux-nbIx' Novitsky">
//   Copyright (c) Roman '4ux-nbIx' Novitsky 2009
// </copyright>
// <summary>
//   Defines the SettingsSelector type.
// </summary>
// --------------------------------------------------------------------------------------------------------------------


namespace SettingsManager
{
  #region Namespace Imports

  using System;
  using System.Collections.Generic;
  using System.Drawing;
  using System.Globalization;
  using System.IO;
  using System.Linq;
  using System.Windows.Forms;

  using ComponentSettingsManagers;

  using JetBrains.ActionManagement;
  using JetBrains.Annotations;
  using JetBrains.IDE;
  using JetBrains.ProjectModel;
  using JetBrains.UI.CommonDialogs;
  using JetBrains.Util;

  using Properties;

  using MessageBox = JetBrains.Util.MessageBox;

  #endregion


  /// <summary>
  /// Describes and manipulates the settings selector.
  /// </summary>
  internal sealed partial class ManageSettingsForm : Form
  {
    #region Constants and Fields

    private readonly IDataContext _dataContext;


    private static Point? _location;
    private static Size? _size;
    private ResharperSettingsManager _settingsManager;
    private SolutionSettingsManager _solutionSettingsManager;

    #endregion


    #region Constructors and Destructors

    /// <summary>
    /// Initializes a new instance of the <see cref="ManageSettingsForm"/> class.
    /// </summary>
    /// <param name="dataContext">
    /// The data context.
    /// </param>
    public ManageSettingsForm([NotNull] IDataContext dataContext)
    {
      _dataContext = dataContext;
      InitializeComponent();

      if (_location.HasValue)
      {
        Location = _location.GetValueOrDefault();
      }

      if (_size.HasValue)
      {
        Size = _size.GetValueOrDefault();
      }

      UpdateControls();
    }

    #endregion


    #region Properties

    /// <summary>
    /// Sets the settings manager.
    /// </summary>
    /// <value>
    /// The settings manager.
    /// </value>
    public ResharperSettingsManager SettingsManager
    {
      set
      {
        _settingsManager = value;

        _settingsFilesTree.SettingsManager = value;
        _settingsFilesTree.Focus();

        _settingsManager.GetSettingsFiles();

        ISolution solution = _dataContext.GetData(DataConstants.SOLUTION);

        if (solution != null)
        {
          _solutionSettingsManager = SolutionSettingsManager.GetInstance(solution);
          _solutionSettingsManager.AutoLoadResharperSettings = false;
          _settingsFilesTree.SolutionSettingsManager = _solutionSettingsManager;
        }

        UpdateControls();
      }
    }

    private bool IsSharedSettingsFileSelected
    {
      get
      {
        return SelectedFile is SharedSettingsFile;
      }
    }

    /// <summary>
    /// Gets the selected file.
    /// </summary>
    /// <value>
    /// The selected file.
    /// </value>
    private SettingsFile SelectedFile
    {
      get
      {
        return _settingsFilesTree.SelectedItem;
      }
    }

    #endregion


    #region Methods

    protected override void OnClosed([NotNull] EventArgs e)
    {
      _location = Location;
      _size = Size;

      if (_solutionSettingsManager == null)
      {
        return;
      }

      _solutionSettingsManager.AutoLoadResharperSettings = true;
    }


    private static string GetSaveLoadSettingsConfirmationMessage(SettingsFile settingsFile, string message, string confirmationText)
    {
      message += "\n" + settingsFile.DisplayName;

      var sharedSettingsFile = settingsFile as SharedSettingsFile;

      if (sharedSettingsFile != null)
      {
        sharedSettingsFile = sharedSettingsFile.ParentSettingsFile;

        while (sharedSettingsFile != null)
        {
          message += ",\n" + sharedSettingsFile.DisplayName;
          sharedSettingsFile = sharedSettingsFile.ParentSettingsFile;
        }
      }


      message += "\n\n" + confirmationText;
      return message;
    }


    private void ConfigureFileAndSaveResharperSettings([NotNull] SettingsFile settingsFile)
    {
      DisableFileSystemMonitoring();

      DialogResult result = ConfigureSettingsFile(settingsFile);

      if (result == DialogResult.OK)
      {
        if (settingsFile.ExternalSettingsContainerFilePath == null)
        {
          var sharedSettingsFile = settingsFile as SharedSettingsFile;

          if (sharedSettingsFile != null)
          {
            sharedSettingsFile.SaveResharperSettings(false);
          }
          else
          {
            settingsFile.SaveResharperSettings();
          }
        }
      }

      EnableFileSystemMonitoring();
    }


    private void EnableFileSystemMonitoring()
    {
      if (_solutionSettingsManager == null)
      {
        return;
      }

      _solutionSettingsManager.ReloadSettings();
    }


    private void DisableFileSystemMonitoring()
    {
      if (_solutionSettingsManager != null)
      {
        _solutionSettingsManager.DisableFileSystemMonitoring();
      }
    }


    private DialogResult ConfigureSettingsFile([NotNull] SettingsFile settingsFile)
    {
      using (var optionsForm = new SettingsFileOptionsForm(settingsFile))
      {
        return optionsForm.ShowDialog(this);
      }
    }


    private void DeleteFileButtonClick([NotNull] object sender, [NotNull] EventArgs e)
    {
      bool result = MessageBox.ShowYesNo(
        "Are you sure you want to remove the selected settings file?", "Confirm Remove", Handle);

      if (!result)
      {
        return;
      }

      SettingsFile selectedSettingsFile = _settingsFilesTree.SelectedItem;
      File.Delete(selectedSettingsFile.Path.FullPath);
    }


    private bool IsValidGlobalSettingsPathSelected()
    {
      var currentFolder = new FileSystemPath(_solutionSettingsManager.Solution.SolutionFilePath.Directory.FullPath);
      var selectedFolder = new FileSystemPath(_folderBrowserDialog.SelectedPath);

      if (currentFolder != selectedFolder && !currentFolder.GetParentDirectories().Contains(selectedFolder))
      {
        MessageBox.ShowError(
          "Invalid folder selected: the global settings file will be unaccessible by the current solution.", 
          "Error", 
          Handle);

        return false;
      }

      string settingsFilePath = Path.Combine(
        _folderBrowserDialog.SelectedPath, SharedSettingsFile.GlobalSettingsFileName);

      if (File.Exists(settingsFilePath))
      {
        MessageBox.ShowError("The global settings file already exists at the specified folder.", "Error", Handle);

        return false;
      }

      return true;
    }


    private void LoadAdvancedMenuItemClick([NotNull] object sender, [NotNull] EventArgs e)
    {
      using (var dialog = new LoadSettingsOptionsDialog())
      {
        DialogResult result = dialog.ShowDialog(this);

        if (result == DialogResult.Cancel)
        {
          return;
        }

        LoadSettings(dialog.SelectedSettingsManagers);
      }
    }


    private void LoadFileButtonClick([NotNull] object sender, [NotNull] EventArgs e)
    {
      LoadSettings(_settingsManager.ComponentSettingsManagers);
    }


    private void LoadSettings([NotNull] IEnumerable<IComponentSettingsManager> selectedSettingsManagers)
    {
      string caption = "Load selected settings?";
      string message = "The following settings file(s) will be loaded:";
      string confirmationText = "Are you sure you want to continue?";

      if (_solutionSettingsManager != null && !IsSharedSettingsFileSelected)
      {
        if (_solutionSettingsManager.SharedSettingsFile != null)
        {
          caption = "Override Shared Settings?";
          confirmationText =
            "Are you sure you want to override the shared solution settings with the settings from the selected file(s)?";
        }
      }

      message = GetSaveLoadSettingsConfirmationMessage(SelectedFile, message, confirmationText);

      if (!MessageBox.ShowYesNo(message, caption, Handle))
      {
        return;
      }

      bool loaded = SelectedFile.LoadResharperSettings(selectedSettingsManagers);

      if (loaded)
      {
        MessageBox.ShowInfo("The file was successfully loaded.", "Settings Loaded", Handle);
      }
    }


    private void OnAddGlobalSettingsMenuItemClick([NotNull] object sender, [NotNull] EventArgs e)
    {
      if (_solutionSettingsManager == null)
      {
        return;
      }

      _folderBrowserDialog.SelectedPath = _solutionSettingsManager.Solution.SolutionFilePath.Directory.FullPath;
      DialogResult result = _folderBrowserDialog.ShowDialog(this);

      if (result != DialogResult.OK)
      {
        return;
      }

      if (!IsValidGlobalSettingsPathSelected())
      {
        return;
      }

      string settingsFilePath = Path.Combine(
        _folderBrowserDialog.SelectedPath, SharedSettingsFile.GlobalSettingsFileName);

      var settingsFile = SharedSettingsFile.Create(_solutionSettingsManager.Solution, settingsFilePath);

      ConfigureFileAndSaveResharperSettings(settingsFile);
    }


    private void OnAddPersonalFileButtonClick([NotNull] object sender, [NotNull] EventArgs e)
    {
      Func<string, string> validator = value =>
                                       {
                                         if (_settingsManager.SettingsFiles.Where(f => f.Name == value).Any())
                                         {
                                           return "A personal settings file with the same name already exists.";
                                         }

                                         char[] invalidFileNameChars = Path.GetInvalidFileNameChars();

                                         return value.ToCharArray().Where(c => invalidFileNameChars.Contains(c)).Any()
                                                  ? "The specified file name contains invalid characters." : null;
                                       };

      using (var form = new PromptWinForm("New Personal Settings File", "File name:", "Personal", validator))
      {
        DialogResult result = form.ShowDialog(this);

        if (result != DialogResult.OK)
        {
          return;
        }

        string fileName = string.Format(
          CultureInfo.InvariantCulture, "{0}.{1}", form.Value, Resources.SettingsFileExtension);

        fileName = Path.Combine(_settingsManager.SettingsFolderPath, fileName);

        var file = SettingsFile.Create(fileName);
        ConfigureFileAndSaveResharperSettings(file);

        UpdateControls();
      }
    }


    private void OnAddSolutionSettingsMenuItemClick([NotNull] object sender, [NotNull] EventArgs e)
    {
      if (_solutionSettingsManager == null)
      {
        return;
      }

      var settingsFile = SharedSettingsFile.Create(_solutionSettingsManager.Solution);
      ConfigureFileAndSaveResharperSettings(settingsFile);
    }


    private void OnConfigureButtonClick([NotNull] object sender, [NotNull] EventArgs e)
    {
      SettingsFile settingsFile = SelectedFile;

      if (settingsFile == null)
      {
        return;
      }

      DisableFileSystemMonitoring();
      ConfigureSettingsFile(settingsFile);
      EnableFileSystemMonitoring();
    }


    private void SaveButtonClick([NotNull] object sender, [NotNull] EventArgs e)
    {
      SettingsFile settingsFile = _settingsFilesTree.SelectedItem;

      if (settingsFile == null)
      {
        return;
      }

      string message = GetSaveLoadSettingsConfirmationMessage(settingsFile, "The following settings file(s) will be updated:", "Are you sure you want to continue?");

      if (!MessageBox.ShowYesNo(message, "Update selected settings?", Handle))
      {
        return;
      }

      if (settingsFile.SaveResharperSettings())
      {
        MessageBox.ShowInfo("The file was successfully updated.", "Success", Handle);
      }
    }


    private void SettingsFilesListSelectedIndexChanged([NotNull] object sender, [NotNull] EventArgs e)
    {
      UpdateControls();
    }


    private void UpdateControls()
    {
      bool isItemSelected = SelectedFile != null;

      _deleteFileButton.Enabled = isItemSelected;
      _saveButton.Enabled = isItemSelected;
      _loadFileSplitButton.Enabled = isItemSelected;
      _confiureButton.Enabled = isItemSelected;
      _addFileButton.Enabled = _settingsManager != null;

      _addPersonalSettingsMenuItem.Enabled = _settingsManager != null ? _settingsManager.IsSettingsFolderValid : false;
      _addGlobalSettingsMenuItem.Enabled = _solutionSettingsManager != null;

      _addSolutionSettingsMenuItem.Enabled = _solutionSettingsManager != null
                                             &&
                                             (_solutionSettingsManager.SharedSettingsFile == null
                                              || _solutionSettingsManager.SharedSettingsFile.IsGlobal);
    }

    #endregion
  }
}